function Create_Cmakelist(hCS,buildInfo)
% Create_Cmakelist(hCS,buildInfo)
%
% Create the CMAKE List files based on the code generated.
% Uses Build Info structure


%% Assumes we enter from top level model, will reject all child-model info
    Current_Dir = pwd;
    if strfind(Current_Dir,'slprj')
        return;
    end
    
    BuildStartDir_List = getBuildDirList(buildInfo);    
    load(fullfile(codertarget.pixhawk.internal.getSpPkgRootDir,'+codertarget/+pixhawk/+CMAKE_Utils/CmakeInfo.mat'));    
    fprintf('Build path: %s \n',BuildStartDir_List{1})

    %% Update buildInfo - not sure if this is needed
    % extList = {'.c' '.C' '.cpp' '.CPP' '.s' '.S'};
    % incExtList = {'.h' '.H', '.hpp'};
    % updateFilePathsAndExtensions(buildInfo, extList, incExtList);

    % By default, findIncludeFiles errors out if finds an unknown
    % header ignoreParseError converts the errors into warnings
    % ignoreMissingIncludes suppresses the warnings.
    findIncludeFiles(buildInfo, ...
                   'extensions', {'*.h' '*.hpp'}, ...
                   'ignoreParseError', true, ...
                   'ignoreMissingIncludes', true);           


    IncludePathDir_List  = getIncludePaths(buildInfo,false)';


    %% Define start and build dir 

    % the zip file will be put in the start dir, the same as the final
    % executable or dll.
    sDir = getSourcePaths(buildInfo, true, {'StartDir'});
    if isempty(sDir)
        sDir = {pwd};
    end
    bDir = getSourcePaths(buildInfo, true, {'BuildDir'});
    if isempty(bDir)
        bDir = {pwd};
    end


    %% Grab paths to add for header file includes - used in CMAKELIST.txt creation
    % Here, we are going to add paths to our CMAKE list. We do not
    % need to add every single path because most of the /firmware/ paths
    % are already included in the build process. Only MathWorks specific
    % paths will get added
    IncludePathDirFiltered_List = [];
    ValidPathToAdd_Keywords = {'$(MATLAB_ROOT)', matlabroot; ...
                               '$(START_DIR)'  , sDir{1} };
    ValidPathToDel_Keywords = {'$(PX4_ROOT)','$(PX4PSP_MODULE_BUILD_OUTPUT)'};
    for i = 1:numel(IncludePathDir_List)  
        addedToPath = false;
        addPths = cellfun(@(x) strfind(IncludePathDir_List{i},x),ValidPathToAdd_Keywords,'UniformOutput', false);
        f = ~cellfun(@isempty, addPths);
        for idx = 1:size(ValidPathToAdd_Keywords,1)
            if f(idx,1)
                IncludePathDirFiltered_List{end+1} = IncludePathDir_List{i};
                IncludePathDirFiltered_List{end} = strrep( IncludePathDirFiltered_List{end} , ValidPathToAdd_Keywords{idx,1}, ValidPathToAdd_Keywords{idx,2});
                addedToPath = true;
                break;
            end
        end
        if ~addedToPath
            delPths = cellfun(@(x) strfind(IncludePathDir_List{i},x),ValidPathToDel_Keywords,'UniformOutput', false);
            addedToPath = (sum(cellfun(@isempty, delPths)) == size(delPths,2));
            % see if we still need to add it to the path...
            if addedToPath
                IncludePathDirFiltered_List{end+1} = IncludePathDir_List{i};
            end
        end
        if addedToPath
            % change to forward slash
            IncludePathDirFiltered_List{end}(IncludePathDirFiltered_List{end}=='\') = '/';
        end
    end


    %% Grab list of all files to export

    FullfilePaths_List = getFullFileList(buildInfo);
    %filter out only the .c files:

    FullfilePathsFiltered_List = [];

    for i = 1:numel(FullfilePaths_List)
       [~, ~, ext] = fileparts(FullfilePaths_List{i});   
       if strcmp(ext,'.c') || strcmp(ext,'.cpp') || strcmp(ext,'.s') || strcmp(ext,'.lib') || strcmp(ext,'.a')
            FullfilePathsFiltered_List{end+1} = FullfilePaths_List{i};
       end
    end

    %% CMAKE Creation    
    writeCMakeListsTxt(hCS,...
                    buildInfo,...
                    IncludePathDirFiltered_List,...
                    FullfilePathsFiltered_List,...
                    Px4PSP_CmakeInfo);


    %% Copy paste files to correct directory    
    FullfilePathsFiltered_List = [FullfilePathsFiltered_List, ...
        fullfile(bDir{1}, 'CMakeLists.txt'), ...    
        ];   
    
    Destination_Dir = Px4PSP_CmakeInfo.Px4_Simulink_Module_Dir;
    
    if (exist(Destination_Dir, 'file'))
        disp('Removing Simulink module CMAKE source directory, adding new content..');        
        if strcmp('glnxa64',computer('arch'))      
            system(['rm -rf ',Destination_Dir,'/*']);
        else        
            system(['del /q "',Destination_Dir,'\*"']);        
        end       
    end
    
    [~, ~, ~] = mkdir(Destination_Dir);
    
    for FileIdx = 1:length(FullfilePathsFiltered_List)
        rc = copyfile(FullfilePathsFiltered_List{FileIdx}, Destination_Dir) ;
        if rc < 0
            error('Error copying generated code into Pixhawk firmware directory: %s',Destination_Dir);
        end
    end


end

%--------------------------------------------------------------------------
% Internal functions
%--------------------------------------------------------------------------
function writeCMakeListsTxt(hCS,...
                            buildInfo,...
                            SL_IncludePaths,...
                            SL_SrcFiles,...
                            Px4PSP_CmakeInfo)

    if Px4PSP_CmakeInfo.isUsingWindows10Bash
        %re-orient path if we're using the Windows 10 Bash prompt so it is
        %a valid path for Ubuntu shell. Make no assumptions about drive
        %letter
        SL_IncludePaths = cellfun(@(x) [lower(x(1)) x(2:end)],SL_IncludePaths,'UniformOutput',false);
        % Added the next line to account for MATLAB SL Include paths not on same
        % drive letter as the pixhawk firmware (e.g. c:\matlab vs e:\px4)

        DesModuleDir = [Px4PSP_CmakeInfo.Px4_Simulink_Module_Dir,'\hfile'];
        if exist(DesModuleDir,'dir')
            rmdir(DesModuleDir,'s');
        end
        for i=1:length(SL_IncludePaths)
            hdir = SL_IncludePaths{i};
            D= dir([hdir,'/*.h']);
            if ~isempty(D)
                copyfile([hdir,'/*.h'],DesModuleDir,'f');
            end
        end
        SL_IncludePaths = {'./hfile'};

    end


%% Create string writer object
hs = codertarget.pixhawk.CMAKE_Utils.StringWriter;

%Load toolchain object - needed for resolving C-flags
MATFileContent = load(fullfile(codertarget.pixhawk.internal.getSpPkgRootDir,'registry','gcc_pixhawk_nuttx_embedded_gmake_win64_v4.6.2.mat'));
tc = MATFileContent.tc;

%% Define C-flags
ConfigType = hCS.Components(8).BuildConfiguration;

%First get the build config type, this returns a string
if ~strcmp(ConfigType,'Specify')
    BuildConfigs = tc.getBuildConfiguration(ConfigType);
    ListConfigs = BuildConfigs.values;

    %Return a cell array each containing a struct element Macro. Need to search
    %for the one that says CFLAGS    
    for i = 1:length(ListConfigs)
        if strcmp(ListConfigs{i}.getMacro,'CFLAGS')
            GetCurrentCFLAGS = ListConfigs{i}.getValue;
        end
    end
    
else
    
    %If the user specified their own custom toolchain flags
    TC_options = hCS.Components(8).CustomToolchainOptions;
    GetCurrentCFLAGS= textscan(TC_options{2},'%s');
    GetCurrentCFLAGS =  cell(GetCurrentCFLAGS{1});      
end

%% Grab all flags from toolchain object
%ARCHWARNINGS
ARCHWARNINGS = tc.getMacro('ARCHWARNINGS');
ARCHWARNINGS_Str = textscan(ARCHWARNINGS,'%s %s');
ARCHWARNINGS_Str = strjoin(ARCHWARNINGS_Str{1});

%ARCHCWARNINGS
ARCHCWARNING = tc.getMacro('ARCHCWARNINGS');
ARCHCWARNING_Str = textscan(ARCHCWARNING,'%s %s');
ARCHCWARNING_Str = strjoin(ARCHCWARNING_Str{1});

%ARCHCWARNING: Append warning flags together
ARCHCWARNING_Str = strrep(ARCHCWARNING_Str,'$(ARCHWARNINGS)',ARCHWARNINGS_Str);


%ARCHCPUFLAGS
ARCHCPUFLAGS = tc.getMacro('ARCHCPUFLAGS_CORTEXM3'); %the ARCHCPUFLAGS flag resolves to ARCHCPUFLAGS_CORTEXM3
ARCHCPUFLAGS_Str = textscan(ARCHCPUFLAGS,'%s %s');
ARCHCPUFLAGS_Str = strjoin(ARCHCPUFLAGS_Str{1});

%ARCHDEFINES
ARCHDEFINES = tc.getMacro('ARCHDEFINES');
ARCHDEFINES_Str = textscan(ARCHDEFINES,'%s %s');
ARCHDEFINES_Str = strjoin(ARCHDEFINES_Str{1});

%ARCHOPTIMIZATION - scan this to see if it exists
if strcmp(ConfigType,'Faster Runs')
    ARCHOPTIMIZATION = tc.getMacro('ARCHOPTIMIZATION');
    ARCHOPTIMIZATION_Str = textscan(ARCHOPTIMIZATION,'%s %s');
    ARCHOPTIMIZATION_Str = strjoin(ARCHOPTIMIZATION_Str{1});
end


%% Header comments
hs.addcr('## This cmakelist.txt file was generated from OnAfterCodegen.m build hook from');
hs.addcr('## the Pixhawk Pilot Support Package');
hs.addcr();

%% Remove source file exemptions - external mode utils.c. Reason is because its not treated as an individual source file in build process

clcReturnVal = strfind(SL_SrcFiles,'ext_serial_utils');
for i=1:numel(clcReturnVal)
    if ~isempty(clcReturnVal{i})
        SL_SrcFiles(i) = []; %remove instance of this source file
    end
end
clcReturnVal = strfind(SL_SrcFiles,'_params.c');
for i=1:numel(clcReturnVal)
    if ~isempty(clcReturnVal{i})
        SL_SrcFiles(i) = []; %remove instance of this source file
    end
end

%% Compiler defines generated from generated code

% Add project specific definitions
def = buildInfo.getDefines;
if ~isempty(def)
    hs.addcr('add_definitions(')
    for k = 1:numel(def)
        hs.add(def{k});
        hs.add(' ');
    end
    hs.addcr(')');
end
hs.addcr();


%% Add include paths from generated code
if ~isempty(SL_IncludePaths)
    hs.addcr('include_directories(')
    for k = 1:numel(SL_IncludePaths)
        hs.add('"');
        hs.add(SL_IncludePaths{k});
        hs.add('"');
        hs.addcr();
    end
    hs.addcr(')')    
end
hs.addcr();


%% Populate px4_add_module
hs.addcr('px4_add_module('); % Start of px4_add_module
hs.addcr(sprintf('MODULE modules__%s','px4_simulink_app'));
hs.addcr(sprintf('MAIN %s','px4_simulink_app'));
hs.addcr(sprintf('STACK_MAIN %d',2000));
hs.addcr('SRCS');

% srcFiles = getSourceFiles(buildInfo, false, false);
for k = 1:numel(SL_SrcFiles)
    [~, name, ext] = fileparts(SL_SrcFiles{k});
    hs.addcr(sprintf('   %s', [name, ext]));
end
    
hs.addcr(sprintf('%s', 'DEPENDS'));
%hs.addcr(sprintf('    %s', 'platforms__common'));
% hs.addcr(sprintf('   %s', ')'));
hs.addcr(')'); % End of px4_add_module
hs.addcr();

% Insert CMAKE Flag over-ride here
hs.addcr('# Over-ride compile flags here: ');
hs.add('set(SL_CUSTOM_FLAGS ');
hs.add(strjoin(GetCurrentCFLAGS));
hs.addcr(')');
hs.addcr();
hs.addcr();
hs.addcr();
hs.addcr('# Macro Flag Expansion');
hs.addcr(['string (REPLACE "$(ARCHCWARNINGS)" "','-w','" SL_CUSTOM_FLAGS "${SL_CUSTOM_FLAGS}")']);
hs.addcr(['string (REPLACE "$(ARCHCPUFLAGS)" "',ARCHCPUFLAGS_Str,'" SL_CUSTOM_FLAGS "${SL_CUSTOM_FLAGS}")']);
hs.addcr(['string (REPLACE "$(ARCHINCLUDES)" " " SL_CUSTOM_FLAGS "${SL_CUSTOM_FLAGS}")']);
hs.addcr(['string (REPLACE "$(INSTRUMENTATIONDEFINES)" " " SL_CUSTOM_FLAGS "${SL_CUSTOM_FLAGS}")']);
hs.addcr(['string (REPLACE "$(ARCHDEFINES)" "',ARCHDEFINES_Str,'" SL_CUSTOM_FLAGS "${SL_CUSTOM_FLAGS}")']);

if strcmp(ConfigType,'Faster Runs')
    hs.addcr(['string (REPLACE "$(ARCHOPTIMIZATION)" "',ARCHOPTIMIZATION_Str,'" SL_CUSTOM_FLAGS "${SL_CUSTOM_FLAGS}")']);
end

hs.addcr(['string (REPLACE ";" " " CMAKE_C_FLAGS "${SL_CUSTOM_FLAGS}")']);
hs.addcr();


hs.write('CMakeLists.txt');
end



